<?php

namespace mpend\models;

use Yii;
use Exception;
use common\helpers\FileHelper;
use common\helpers\IpHelper;
use common\models\Attachment;
use yii\web\UploadedFile;
use Imagine\Exception\NotSupportedException;
use common\validators\FileValidator;
use yii\helpers\ArrayHelper;

/**
 * 图片上传模型
 * UploadImage is the model behind the upload form.
 */
class UploadAttach extends \common\base\Model {

    use \common\traits\Constants;

    const SCOPE_DEFAULT = 'default';
    const SCOPE_USER = 'user';
    const SCOPE_AUTHENT = 'authent';
    const SCOPE_ACTIVITY = 'activity';
    //
    const FORMAT_IMAGE = 'image';
    const FORMAT_VIDEO = 'video';
    const FORMAT_AUDIO = 'audio';
    const FORMAT_MEDIA = 'media';
    const FORMAT_FILE = 'file';

    /**
     * @name $user_id
     * @var integer 用户UID
     */
    public $user_id = 0;

    /**
     * @name $scope
     * @var string 应用范围
     */
    public $scope = 'default';

    /**
     * @name $scope
     * @var string 应用范围
     */
    public $format = self::FORMAT_IMAGE;

    /**
     * @name $streamFile 待上传文件
     * @var \yii\web\UploadedFile file attribute
     */
    public $streamFile = null;

    /**
     * @name $channel
     * @var string 上传通道，支持通道阿里云OSS:、服务器SFTP
     */
    public $channel = 'OSS';

    /**
     * @name $cut
     * @var integer 是否启用图片压缩
     */
    public $cut = 0;

    /**
     * @name $uploadPath
     * @var string 上传根目录别名
     */
    public $uploadPath = '@uploads';

    /**
     * @return array the validation rules.
     */
    public function rules() {
        return [
            [['streamFile'], 'required'],
            [['user_id'], 'integer'],
            ['scope', 'in', 'range' => static::getConstants('scope'), 'message' => '{attribute}不在允许范围内'],
            ['format', 'in', 'range' => static::getConstants('format'), 'message' => '{format}不在允许范围内'],
            ['streamFile', 'validateFileMimeType'],
        ];
    }

    public static function getMimeType($file) {
        $extension = mb_strtolower($file->extension, 'UTF-8');
        $mimeType = FileHelper::getMimeType($file->tempName, null, false);
        Yii::error([
            $extension,
            $file,
            $mimeType,
        ]);
        if ($mimeType) {
            $extensionsByMimeType = FileHelper::getExtensionsByMimeType($mimeType);
            if (!in_array($extension, $extensionsByMimeType, true)) {
                Yii::error([
                    $extension,
                    $extensionsByMimeType,
                ]);
            }
        }
    }

    public function validateFileMimeType($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        $validator = new FileValidator();
        if ($this->format == static::FORMAT_IMAGE) {
            $validator->mimeTypes = $this->getFileMimeTypes($this->format);
            $validator->wrongMimeType = '不支持的图片格式';
        } elseif ($this->format == static::FORMAT_MEDIA) {
            $validator->mimeTypes = $this->getFileMimeTypes($this->format);
            $validator->wrongMimeType = '不支持的媒体文件格式';
        } elseif ($this->format == static::FORMAT_VIDEO) {
            $validator->extensions = ['mp4'];
            $validator->wrongExtension = '不支持的视频格式';
        } elseif ($this->format == static::FORMAT_AUDIO) {
            $validator->extensions = ['mp3'];
            $validator->wrongExtension = '不支持的音频格式';
        } elseif ($this->format == static::FORMAT_FILE) {
            $validator->extensions = [
                'doc',
                'docx',
                'xls',
                'xlsx',
                'pdf',
                'ppt',
                'txt',
                'zip',
                'rar',
            ];
            $validator->wrongExtension = '不支持的文件格式';
        }
        $validator->validateAttribute($this, $attribute);
    }

    public function getFileMimeTypes($format) {
        $mimeTypes = [
            self::FORMAT_IMAGE => [
                'image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/svg+xml', 'image/vnd.wap.wbmp', 'image/webp',
            ],
            self::FORMAT_VIDEO => [
                'video/mp4',
            ],
            self::FORMAT_AUDIO => [
                'audio/mpeg', 'audio/x-wav',
            ],
            self::FORMAT_MEDIA => [
                'image/jpeg',
                'image/png',
                'image/gif',
                'image/bmp',
                'image/svg+xml',
                'image/vnd.wap.wbmp',
                'image/webp',
                'video/mp4',
                'audio/mpeg',
                'audio/x-wav',
            ],
            self::FORMAT_FILE => [
                'text/plain',
                'application/pdf',
                'application/vnd.ms-powerpoint',
                'application/vnd.ms-powerpoint.presentation.macroenabled.12',
                'application/vnd.ms-excel',
                'application/vnd.ms-excel.addin.macroenabled.12',
                'application/vnd.ms-excel.sheet.binary.macroenabled.12',
                'application/vnd.ms-excel.sheet.macroenabled.12',
                'application/vnd.ms-excel.template.macroenabled.12',
                'application/vnd.openxmlformats-officedocument.presentationml.presentation',
                'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
                'application/xml',
                'application/xslt+xml',
                'application/zip',
            ],
        ];
        return ArrayHelper::getValue($mimeTypes, $format, []);
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels() {
        return [
            'user_id' => '用户ID',
            'scope' => '应用场景',
            'format' => '文件格式',
            'streamFile' => '文件',
        ];
    }

    public function upload() {
        if (!$this->validate()) {
            $this->validateError('文件上传失败');
        }
        $file = $this->streamFile;
        if (!($file instanceof UploadedFile)) {
            $this->validateError('文件上传失败');
        }
        $width = 0;
        $height = 0;
        $extension = $file->getExtension();
        $mimeType = '';
        if ($this->format == static::FORMAT_IMAGE) {
            try {
                $size = getimagesize($file->tempName);
                if ($size === false) {
                    throw new NotSupportedException('文件格式错误，请上传图片文件');
                }
                list($width, $height, $type) = $size;
            } catch (Exception $exc) {
                $this->validateError($exc->getMessage());
            }
            if (!$type) {
                $this->validateError('图片文件类型错误');
            }
            $extension = image_type_to_extension($type);
            if (!$extension) {
                $this->validateError($extension . '图片文件格式错误');
            }
            $mimeType = image_type_to_mime_type($type);
        }
        $relativeDir = '/attachments/' . $this->scope . '/' . date('Ym/d') . '/';
        $absoluteDir = Yii::getAlias($this->uploadPath . $relativeDir);
        FileHelper::createDirectory($absoluteDir);
        $filename = FileHelper::buildUploadFileName($extension);
        $file->saveAs($absoluteDir . $filename);

        $relativePath = $relativeDir . $filename;
        if ($file->getHasError()) {
            $this->dumpError('文件保存失败', $file->error);
        }
        if (YII_ENV_PROD) {
            if (strpos(Yii::$app->id, 'mpend') !== false) {
                /* @var $wechat \common\components\wechat\MpWechat */
                $wechat = Yii::$app->wechatMp;
                if (!$wechat->checkImgSec($absoluteDir . $filename, $mimeType)) {
                    return $this->dumpError('上传文件包含违规信息');
                }
            }
            try {
                /* @var $oss \common\components\aliyun\AliyunOSS */
                $oss = Yii::$app->alioss;
                $oss->uploadFile(ltrim($relativePath, '/'), $absoluteDir . $filename, 'public-read');
            } catch (Exception $e) {
                return $this->dumpError($e->getMessage());
            }
        }
        $attachs = new Attachment();
        $attachs->attributes = [
            'user_id' => $this->user_id,
            'path' => $relativePath,
            'original_name' => $file->name,
            'channel' => $this->channel,
            'size' => $file->size,
            'isimage' => 1,
            'width' => $width,
            'height' => $height,
            'ip' => IpHelper::ip(),
        ];
        $attachs->generateToken();
        if (!$attachs->save()) {
            return $attachs->dumpError();
        }
        return $attachs->toArray();
    }

}
